package View;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JPanel;

import objects.Gene;
import objects.Line;
import objects.Subset;
import objects.Treatment;
import objects.ValidPosition;
import objects.alignments.Alignment;
import objects.alignments.CollapsedAlignment;
import objects.alignments.IntronAlignment;
import objects.alignments.IntronCollapsedAlignment;
import objects.alignments.SingleAlignment;
import objects.alignments.SpliceAlignment;
import objects.alignments.SpliceCollapsedAlignment;
import objects.alignments.Subset0Alignment;

import Control.Controller;
import Control.Zoomable;

public class Subset0Viewport extends JPanel {

	private static final long serialVersionUID = -1653381494281241305L;
	private static Subset0Viewport instance = null;
	private Zoomable z;
	private List<Line> lines = null;
	private int lineTreatments = 0;

	protected Subset0Viewport() {
		lines = new ArrayList<Line>();
		z = Zoomable.getInstance();
		z.registerComponent(this);
	}

	public static Subset0Viewport getInstance() {
		if (instance == null) {
			instance = new Subset0Viewport();
		}
		return instance;
	}

	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);

		// Get the Gene to paint
		Gene gene = Controller.getInstance().getCurrentGene();
		if (gene == null) {
			return;
		}

		// The total distance of the gene + offset data
		int totalDistance = Controller.getInstance().getCalculatedDistance();
		if (!z.isSet())
			z.autoZoom(totalDistance);
		// Change the total distance to work with zooming
		totalDistance = z.calcDist(totalDistance);
//		System.out.println ("Dimensions have changed");
//		System.out.println ("New Dimensions: " + getWidth() + " v. " + getHeight());
//		System.out.println (" Total Distance: " + totalDistance);

		// Draw the Subset information
		if (Controller.getInstance().treatmentSize() != 0)
			drawSubset0(gene, z.calcDist(Controller.getInstance().getOffset()),
					0, getHeight());

		this.setPreferredSize(new Dimension(totalDistance, getHeight()));
	}

	/**
	 * Draws the information related to Subset 0, most importantly the alignment
	 * details.
	 * 
	 * @param gene
	 *            The current active gene
	 * @param x
	 *            The offset x to start drawing the Subset information at (the
	 *            start of the gene)
	 * @param y
	 *            The offset y to start drawing the Subset 0 information at
	 * @param maxHeight
	 *            The maximum height we get to display the alignment information
	 */

	private void drawSubset0(Gene gene, int x, int y, int maxHeight) {
		// Draw a shadow at the gene site
		Graphics2D g2d = (Graphics2D) this.getGraphics();
		g2d.setColor(new Color(230, 230, 230));
		g2d.fillRect(x, y, z.calcDist(gene.getValidDistance()), maxHeight);

		// Combines the subsets once and online once, unless there has been an
		// update.
		if (lines.size() == 0
				|| lineTreatments != Controller.getInstance().treatmentSize()) {
			combineSubset0(gene);
		}

		for (Line l : lines) {
			// Draw the Line:
			g2d.setColor(new Color(167, 219, 216));
			g2d.drawLine(0, y + l.getID() * 20 + 2, getWidth(), y + l.getID()
					* 20 + 2);

			// Draw the Alignments:
			for (Subset0Alignment alignment : l.getAlignments()) {
				alignment.draw(g2d, x, y + l.getID() * 20);

				// Color insideColor =
				// alignment.getParent().getTreatmentParent().getColor();
				// drawAlignment(insideColor, g2d, alignment, x, y + l.getID() *
				// 20, 4);
			}
		}

		int offset = Line.getMaxID();
		this.setSize(new Dimension(WIDTH, y + offset * 20 + 40));
		this.setPreferredSize(new Dimension(WIDTH, y + offset * 20 + 40));
	}

	private void combineSubset0(Gene activeGene) {
		// Get rid of the old data. Another Treatment has been loaded (therefore
		// it's out of date)
		lines = new ArrayList<Line>();
		Line.resetMaxID();

		// Combine the Active Treatments into one List
		List<Integer> activeTreatments = Controller.getInstance()
				.getActiveTreatments();
		lineTreatments = activeTreatments.size();

		List<Subset0Alignment> all = new ArrayList<Subset0Alignment>();
		for (int treatmentID : activeTreatments) {
			Treatment t = activeGene.getTreatmentByID(treatmentID);

			Subset sub0 = t.getSubsetByID(0);
			List<Alignment> alignments = new ArrayList<Alignment>(sub0
					.getAllAlignments().values());
			for (Alignment a : alignments) {
				all.add((Subset0Alignment) a);
			}
		}

		// Sort all of the alignments by beginning.
		Collections.sort(all);		
		
		// Collapse all of the Alignments
		List<Subset0Alignment> collapsed = collapseAlignments(all);
		
		for (Subset0Alignment a : all) {
			Line lineNum = null;
			for (Line line : lines) {
//				if (line.isLoadable(a)) {
//					line.addPosition(a);
//					lineNum = line;
//					break;
//				}
//				if (line.collapseAlignments(a)) {
//					lineNum = line;
//					break;
//				}
			}
			if (lineNum == null) {
				lineNum = new Line();
				lineNum.addPosition(a);
				lines.add(lineNum);
			}
		}

//		 for (Line l: lines) {
//			 System.out.println ("Line Number: " + l.getID());
//			 for (Alignment a: l.getAlignments()) {
//				 System.out.println (" Alignment " +
//						 a.getStart());
//			 }
//			 System.out.println ("------------");
//		 }
//		 System.out.println ("------------\n\n\n");
	}
	
	private List<Subset0Alignment> collapseAlignments(List<Subset0Alignment> all) 
	{
		int index = 0;
		for (Subset0Alignment one : all) 
		{
			
			for (Subset0Alignment two : all) 
			{
				if (CollapsedAlignment.isCandidateAddition(one, two)) {
					all.remove(one);
					all.remove(two);
					all.add(index, SingleAlignment.collapse(one, two));
				}
			}
			index++;
		}
		
		return all;
//		
//		Subset0Alignment intersection = null;
//		for (Subset0Alignment alignment : taken) {
//			ValidPosition position = alignment.getMaxBound();
//			if (position.intersects(a.getMaxBound())) {
//				intersection = alignment;
//				break;
//			}
//		}
//		// Could not find a place where it intersects, therefore it's not
//		// collapsible
//		if (intersection == null
//				|| !CollapsedAlignment.isCandidateAddition(intersection, a))
//			return false;
//
//		// Create a collapsed alignment object to combine the two alignment
//		CollapsedAlignment cluster = null;
//		if (intersection instanceof CollapsedAlignment) {
//			cluster = (CollapsedAlignment) intersection;
//		}
//		if (cluster == null) {
//			if (intersection instanceof IntronAlignment)
//				cluster = new IntronCollapsedAlignment(intersection);
//			else if (intersection instanceof SpliceAlignment)
//				cluster = new SpliceCollapsedAlignment(intersection);
//			else
//				System.out
//						.println("Intersection wasn't intron or splice site..");
//		}
//
//		cluster.addAlignment(a);
//
//		taken.remove(intersection);
//		taken.add(cluster);
//
//		return true;
	}

	private void drawAlignment(Color color, Graphics g, Subset0Alignment a,
			int x, int y, int maxHeight) {
		Graphics2D g2d = (Graphics2D) g;
		List<ValidPosition> validPositions = a.getValidPositions();
		int oldOffset = 0;
		for (ValidPosition vp : validPositions) {
			g2d.setColor(color);
			vp.x = x + z.calcDist(vp.start);
			vp.y = y;
			vp.width = z.calcDist(vp.getDistance());
			vp.height = maxHeight;
			g2d.fill(vp);
			g2d.setColor(new Color(100, 100, 100));
			g2d.draw(vp);
			if (oldOffset != 0) {
				g2d.setColor(new Color(100, 100, 100));
				g2d.drawLine(oldOffset, y + maxHeight / 2,
						x + z.calcDist(vp.start), y + maxHeight / 2);
			}
			oldOffset = x + z.calcDist(vp.end);
		}
	}
}
